// --------------------------------------------------------------------------------------------------------------------
// <copyright file="SPWebHelper.cs" company="Collaboris Ltd.">
//   Copyright (c) Collaboris Ltd. All rights Reserved.
// </copyright>
// <summary>
//   Defines the SPWebPartsHelper type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Collaboris.SharePoint.Wss.WebParts
{
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Web.UI.WebControls.WebParts;

    using Collaboris.Utils;

    using Files;

    using Microsoft.SharePoint;
    using Microsoft.SharePoint.WebPartPages;

    using WebPart=System.Web.UI.WebControls.WebParts.WebPart;
    using System.Reflection;

    /// <summary>
    /// Adds helper methods to the Sharepoint <see cref="SPWeb"/> class.
    /// </summary>
    public class SPWebPartHelper : WssHelperBase
    {
        /// <summary>
        /// Connects the web parts.
        /// </summary>
        /// <param name="web">The web.</param>
        /// <param name="relativeUrlToPage">Name of the page.</param>
        /// <param name="scope">The scope.</param>
        /// <param name="providerWebPartId">The provider web part id.</param>
        /// <param name="consumerWebPartId">The consumer web part id.</param>
        /// <param name="providerConnId">The provider id.</param>
        /// <param name="consumerConnId">The consumer id.</param>
        /// <param name="transformer">The transformer. optional</param>
        public static void ConnectWebParts( SPWeb web, 
                                            string relativeUrlToPage, 
                                            PersonalizationScope scope, 
                                            string providerWebPartId, 
                                            string consumerWebPartId,
                                            string providerConnId, 
                                            string consumerConnId,
                                            WebPartTransformer transformer)
        {
            TraceHelper.TraceMethodStart(TraceSwitch, "SPWebPartHelper", "ConnectWebParts");
            ValidationHelper.VerifyObjectArgument(web, "web");
            ValidationHelper.VerifyStringArgument(providerConnId, "providerConnId");
            ValidationHelper.VerifyStringArgument(consumerConnId, "consumerConnId");
            ValidationHelper.VerifyObjectArgument(web, "web");

            if (relativeUrlToPage.StartsWith("/"))
                relativeUrlToPage = relativeUrlToPage.Substring(1);

            // Get hold of the Pages Web Part Manager.
            using (SPLimitedWebPartManager mgr = web.GetLimitedWebPartManager(relativeUrlToPage, scope))
            {

                // hook into the web parts.
                Microsoft.SharePoint.WebPartPages.WebPart providerWebPart =
                    (Microsoft.SharePoint.WebPartPages.WebPart)mgr.WebParts[providerWebPartId];
                ValidationHelper.VerifyObjectArgument(providerWebPart, "providerWebPart");

                Microsoft.SharePoint.WebPartPages.WebPart consumerWebPart =
                    (Microsoft.SharePoint.WebPartPages.WebPart)mgr.WebParts[consumerWebPartId];
                ValidationHelper.VerifyObjectArgument(consumerWebPart, "consumerWebPart");

                // now lets hook into the connections
                ConsumerConnectionPoint consumerConnectionPoint =
                    mgr.GetConsumerConnectionPoints(consumerWebPart)[consumerConnId];
                ValidationHelper.VerifyObjectArgument(consumerConnectionPoint, "consumerConnectionPoint");

                ProviderConnectionPoint providerConnectionPoint =
                    mgr.GetProviderConnectionPoints(providerWebPart)[providerConnId];
                ValidationHelper.VerifyObjectArgument(providerConnectionPoint, "providerConnectionPoint");

                if (transformer != null)
                {
                    // lets go and add the connection.
                    mgr.SPConnectWebParts(
                        providerWebPart, providerConnectionPoint, consumerWebPart, consumerConnectionPoint, transformer);
                }
                else
                {
                    // lets go and add the connection.
                    mgr.SPConnectWebParts(
                        providerWebPart, providerConnectionPoint, consumerWebPart, consumerConnectionPoint);
                    
                }

                mgr.Web.Dispose();
            }

            TraceHelper.TraceMethodEnd(TraceSwitch, "SPWebPartHelper", "ConnectWebParts");
        }

        /// <summary>
        /// Adds the web parts.
        /// </summary>
        /// <param name="web">The web.</param>
        /// <param name="file">The file.</param>
        /// <param name="webPartZoneId">The web part zone.</param>
        /// <param name="webParts">The web parts.</param>
        /// <param name="replace">if set to <c>true</c> [replace].</param>
        /// <param name="scope">The scope.</param>
        public static void AddWebParts(SPWeb web, SPFile file, 
                                        List<Microsoft.SharePoint.WebPartPages.WebPart> webParts, string webPartZoneId, 
                                        bool replace, PersonalizationScope scope)
        {
            TraceHelper.TraceMethodStart(TraceSwitch, "SPWebPartHelper", "AddWebParts");

            ValidationHelper.VerifyObjectArgument(web, "web");
            ValidationHelper.VerifyObjectArgument(file, "file");
            ValidationHelper.VerifyObjectArgument(webParts, "webParts");
            ValidationHelper.VerifyStringArgument(webPartZoneId, "webPartZoneId");

            using (SPLimitedWebPartManager mgr = file.GetLimitedWebPartManager(scope))
            {
                List<WebPart> webPartsInZone = GetWebPartsInZone(web, file, webPartZoneId, scope);

                int index = 0;
                if (webPartsInZone != null)
                {
                    index = webPartsInZone.Count;
                }

                foreach (WebPart webPart in webParts)
                {
                    mgr.AddWebPart(webPart, webPartZoneId, index);
                    index++;
                }

                mgr.Web.Dispose();
               
            }
            
            TraceHelper.TraceMethodEnd(TraceSwitch, "SPWebPartHelper", "AddWebParts");
        }

        /// <summary>
        /// Gets the web parts in zone.
        /// </summary>
        /// <param name="web">The web.</param>
        /// <param name="file">The file.</param>
        /// <param name="webPartZoneId">The web part zone id.</param>
        /// <param name="scope">The scope.</param>
        /// <returns></returns>
        public static List<WebPart> GetWebPartsInZone(SPWeb web, SPFile file,
                                                            string webPartZoneId,
                                                            PersonalizationScope scope)
        {
            TraceHelper.TraceMethodStart(TraceSwitch, "SPWebPartHelper", "GetWebPartsInZone");

            ValidationHelper.VerifyObjectArgument(web, "web");
            ValidationHelper.VerifyObjectArgument(file, "file");
            ValidationHelper.VerifyStringArgument(webPartZoneId, "webPartZoneId");

            List<WebPart> webPartList = new List<WebPart>();

            using (SPLimitedWebPartManager mgr = file.GetLimitedWebPartManager(scope))
            {
                foreach (WebPart webPart in mgr.WebParts)
                {
                    string zoneId = mgr.GetZoneID(webPart);
                    if (zoneId.ToLower() == webPartZoneId.ToLower())
                    {
                        webPartList.Add(webPart);
                    }
                }
            }

            TraceHelper.TraceMethodEnd(TraceSwitch, "SPWebPartHelper", "GetWebPartsInZone");

            return webPartList;
        }


        public static void AddWebParts(SPWeb web, string folderUrl, string pageName,
                                        List<Microsoft.SharePoint.WebPartPages.WebPart> webParts, string webPartZoneId,
                                        bool replace, PersonalizationScope scope)
        {
            TraceHelper.TraceMethodStart(TraceSwitch, "SPWebPartHelper", "AddWebParts");

            // get the file
            SPFile targetFile = SPFileHelper.GetFile(web, folderUrl, pageName);

            AddWebParts(web, targetFile, webParts, webPartZoneId,replace, scope);

            TraceHelper.TraceMethodEnd(TraceSwitch, "SPWebPartHelper", "AddWebParts");
        }

        /// <summary>
        /// Sets the web part properties.
        /// </summary>
        /// <param name="web">The web.</param>
        /// <param name="relativeUrlToPage">Name of the page.</param>
        /// <param name="webPartID">The web part ID.</param>
        /// <param name="scope">The scope.</param>
        /// <param name="properties">The properties.</param>
         public static void SetWebPartProperties(SPWeb web,
                                                string relativeUrlToPage,
                                                string webPartID,
                                                PersonalizationScope scope,
                                                SerializableObjectDictionary<string> properties)
        {
            TraceHelper.TraceMethodStart(TraceSwitch, "SPWebPartHelper", "SetWebPartProperties");
            ValidationHelper.VerifyObjectArgument(web, "web");
            ValidationHelper.VerifyStringArgument(relativeUrlToPage, "pageName");
            ValidationHelper.VerifyStringArgument(webPartID, "webPartID");
            ValidationHelper.VerifyObjectArgument(scope, "scope");
            ValidationHelper.VerifyObjectArgument(properties, "properties");

            //WebPart webPart = GetWebPartFromPage(web, pageName, webPartID, scope);
            using (SPLimitedWebPartManager mgr = web.GetLimitedWebPartManager(relativeUrlToPage, scope))
            {
                WebPart webPart = mgr.WebParts[webPartID];

                if (webPart == null)
                {
                    TraceHelper.TraceWarning(
                        TraceSwitch, "SPWebPartHelper", "WebPart : {0} in the Page {1} not found.", webPartID, relativeUrlToPage);
                }
                else
                {
                    PropertyInfo[] webPartProperties = webPart.GetType().GetProperties();
                    foreach (string propertyName in properties.Keys)
                    {
                        foreach (PropertyInfo webPartProperty in webPartProperties)
                        {
                            if (webPartProperty.Name.Equals(propertyName))
                            {
                                webPartProperty.SetValue(webPart, properties.Get<object>(propertyName), null);
                                break;
                            }
                        }
                    }
                    
                    mgr.SaveChanges(webPart);
                }
                mgr.Web.Dispose();
            }

            TraceHelper.TraceMethodEnd(TraceSwitch, "SPWebPartHelper", "SetWebPartProperties");
        }

        /// <summary>
        /// Gets the web part from page.
        /// </summary>
        /// <param name="web">The web.</param>
        /// <param name="relativeUrlToPage">Name of the page.</param>
        /// <param name="webPartID">The web part ID.</param>
        /// <param name="scope">The scope.</param>
        /// <returns></returns>
        public static WebPart GetWebPartFromPage(SPWeb web, 
                                                 string relativeUrlToPage, 
                                                 string webPartID, 
                                                 PersonalizationScope scope)
        {
            TraceHelper.TraceMethodStart(TraceSwitch, "SPWebPartHelper", "GetWebPartFromPage");                     
            ValidationHelper.VerifyObjectArgument(web, "web");
            ValidationHelper.VerifyStringArgument(relativeUrlToPage, "relativeUrlToPage");            
            ValidationHelper.VerifyStringArgument(webPartID, "webPartID");
            ValidationHelper.VerifyObjectArgument(scope, "scope");

            WebPart webPart = null;

            if (relativeUrlToPage.StartsWith("/"))
                relativeUrlToPage = relativeUrlToPage.Substring(1);

            // Get hold of the Pages Web Part Manager.
            using (SPLimitedWebPartManager mgr = web.GetLimitedWebPartManager(relativeUrlToPage, scope))
            {
                webPart = mgr.WebParts[webPartID];
                mgr.Web.Dispose();
            }

            if (webPart == null)
            {
                TraceHelper.TraceWarning(TraceSwitch, "SPWebPartHelper", 
                                            "WebPart : {0} in the Page {1} not found.", 
                                            webPartID, relativeUrlToPage);
            }

            TraceHelper.TraceMethodEnd(TraceSwitch, "SPWebPartHelper", "GetWebPartFromPage");
            return webPart;
        }

        /// <summary>
        /// Removes the web parts.
        /// </summary>
        /// <param name="web">The web.</param>
        /// <param name="relativeUrlToPage">The relativeUrlToPage.</param>
        /// <param name="webPartIds">The web parts.</param>
        /// <param name="scope">The scope.</param>
        public static void RemoveWebParts(SPWeb web, string relativeUrlToPage, List<string> webPartIds, PersonalizationScope scope, bool removeAll)
        {
            TraceHelper.TraceMethodStart(TraceSwitch, "SPWebPartHelper", "AddWebParts");

            ValidationHelper.VerifyObjectArgument(web, "web");
            ValidationHelper.VerifyStringArgument(relativeUrlToPage, "webPartPageRelativeUrl");
          

            if (relativeUrlToPage.StartsWith("/"))
                relativeUrlToPage = relativeUrlToPage.Substring(1);

            //WebPart webPart = GetWebPartFromPage(web, pageName, webPartID, scope);
            using (SPLimitedWebPartManager mgr = web.GetLimitedWebPartManager(relativeUrlToPage, scope))
            {
                if (removeAll)
                {
                    TraceHelper.TraceInfo(
                     TraceSwitch, "SPWebPartHelper", "Deleting ALL web parts from this page :'{0}'", relativeUrlToPage);
                 
                    foreach (WebPart webPart in mgr.WebParts)
                    {
                        mgr.DeleteWebPart(webPart);
                    }
                }
                else
                {
                    foreach (string webPartId in webPartIds)
                    {
                        if (!string.IsNullOrEmpty(webPartId))
                        {
                            WebPart webPart = mgr.WebParts[webPartId];
                            if (webPart != null)
                            {
                                TraceHelper.TraceInfo(
                                    TraceSwitch, "SPWebPartHelper", "Deleting web part with this id :'{0}'", webPartId);
                                mgr.DeleteWebPart(webPart);
                            }
                        }
                    }
                }

                mgr.Web.Dispose();
            }

            TraceHelper.TraceMethodEnd(TraceSwitch, "SPWebPartHelper", "AddWebParts");
        }

        /// <summary>
        /// Gets the connections for web part.
        /// </summary>
        /// <param name="web">The web.</param>
        /// <param name="relativeUrlToPage">The relative URL to page.</param>
        /// <param name="scope">The scope.</param>
        /// <param name="webPartId">The web part id.</param>
        /// <param name="consumerConnections">The consumer connections.</param>
        /// <param name="providerConnections">The provider connections.</param>
        public static void GetConnectionsForWebPart(SPWeb web,
                                    string relativeUrlToPage,
                                    PersonalizationScope scope,
                                    string webPartId,
                                    out List<SPWebPartConnection> consumerConnections,
                                    out List<SPWebPartConnection> providerConnections)
        {
            TraceHelper.TraceMethodStart(TraceSwitch, "SPWebPartHelper", "ConnectWebParts");
            ValidationHelper.VerifyObjectArgument(web, "web");
            ValidationHelper.VerifyStringArgument(webPartId, "webPartId");
            ValidationHelper.VerifyObjectArgument(web, "web");

            if (relativeUrlToPage.StartsWith("/"))
                relativeUrlToPage = relativeUrlToPage.Substring(1);

            // Get hold of the Pages Web Part Manager.
            using (SPLimitedWebPartManager mgr = web.GetLimitedWebPartManager(relativeUrlToPage, scope))
            {
                // hook into the web parts.
                Microsoft.SharePoint.WebPartPages.WebPart webPart =
                    (Microsoft.SharePoint.WebPartPages.WebPart)mgr.WebParts[webPartId];
                ValidationHelper.VerifyObjectArgument(webPartId, "webPartId");
                
                consumerConnections = new List<SPWebPartConnection>();
                providerConnections = new List<SPWebPartConnection>();
                foreach (SPWebPartConnection connection in mgr.SPWebPartConnections)
                {
                    if (connection.Consumer.ID == webPart.ID)
                    {
                        consumerConnections.Add(connection);                        
                    }

                    if (connection.Provider.ID == webPart.ID)
                    {
                        providerConnections.Add(connection);
                    }
                }
            }
        }
    }
}
